/**
 *  Copyright (C) 2010 Travis Brown
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.scalaq.q.implicit;

import java.util.List;

public class Coordinate {
  private final double lng;
  private final double lat;
    
  public Coordinate(double lat, double lng) {
    this.lng = lng;
    this.lat = lat;
  }

  public static Coordinate fromRadians(double lat, double lng) {
    return new Coordinate(lat, lng);
  }

  public static Coordinate fromDegrees(double lat, double lng) {
    return new Coordinate(lat * Math.PI / 180.0, lng * Math.PI / 180.0);
  }

  public double getLat() {
    return this.lat;
  }

  public double getLng() {
    return this.lng;
  }

  public double getLatDegrees() {
    return this.lat * 180.0 / Math.PI;
  }

  public double getLngDegrees() {
    return this.lng * 180.0 / Math.PI;
  }

  public String toString() {
    return this.getLatDegrees() + " " + this.getLngDegrees();
  }

  public double distance(Coordinate other) {
    return Math.acos(Math.sin(this.lat) * Math.sin(other.lat)
       + Math.cos(this.lat) * Math.cos(other.lat) * Math.cos(other.lng - this.lng));
  }

  /**
   * Compute the approximate centroid by taking the average of the latitudes
   * and longitudes.
   */
  public static Coordinate centroid(List<Coordinate> coordinates) {
    int n = coordinates.size();

    double latSins = 0.0;
    double latCoss = 0.0;
    double lngSins = 0.0;
    double lngCoss = 0.0;

    for (int i = 0; i < n; i++) {
      Coordinate coordinate = coordinates.get(i);
      latSins += Math.sin(coordinate.lat);
      latCoss += Math.cos(coordinate.lat);
      lngSins += Math.sin(coordinate.lng);
      lngCoss += Math.cos(coordinate.lng);
    }

    latSins /= n;
    latCoss /= n;
    lngSins /= n;
    lngCoss /= n;

    double lat = Math.atan2(latSins, latCoss);
    double lng = Math.atan2(lngSins, lngCoss);

    return Coordinate.fromRadians(lat, lng);
  }
}

